package com.coocaa.app.lib.cleaner.mgr.impl;

import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;

import com.coocaa.app.lib.cleaner.deleter.apk.ApkDeleterFactory;
import com.coocaa.app.lib.cleaner.deleter.other.OtherDataDeleterFactory;
import com.coocaa.app.lib.cleaner.deleter.pkgcache.PackageCacheDeleterFactory;
import com.coocaa.app.lib.cleaner.deleter.pkgdata.PackageDataDeleterFactory;
import com.coocaa.app.lib.cleaner.deleter.uninstall.AutoUninstallFactory;
import com.coocaa.app.lib.cleaner.mgr.Cleaner;
import com.coocaa.app.lib.cleaner.mgr.DataHolder;
import com.coocaa.app.lib.cleaner.mgr.DataLoader;
import com.coocaa.app.lib.cleaner.scanner.AbstractScanner;
import com.coocaa.app.lib.cleaner.scanner.ScanRunner;
import com.coocaa.app.lib.cleaner.scanner.ScanRunnerFactory;
import com.coocaa.app.lib.cleaner.u.AsyncReturn;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.CountDownLatch;


/**
 * Created by lu on 17-4-11.
 */

public class CleanerImpl implements Cleaner, ScanRunner.ScanRunnerListener {
    private static final DataHolder DATA_HOLDER = DataHolderImpl.instance;
    private static final DataLoader DATA_LOADER = DataHolderImpl.instance;

    private CleanerListener listener;

    private ScanRunner scanRunner = ScanRunnerFactory.factory.create();

    private Context mContext;


    final private PackageDataDeleterFactory.PackageDataDeleter packageDataDeleter = PackageDataDeleterFactory.factory.create();
    final private PackageCacheDeleterFactory.PackageCacheDeleter packageCacheDeleter = PackageCacheDeleterFactory.factory.create();
    final private ApkDeleterFactory.ApkDeleter apkDeleter = ApkDeleterFactory.factory.create();
    final private OtherDataDeleterFactory.OtherDataDeleter otherDataDeleter = OtherDataDeleterFactory.factory.create();
    final private AutoUninstallFactory.IAutoUninstallManager autoUninstallManager;

    public CleanerImpl(Context context) {
        mContext = context;
        scanRunner.init(mContext);

        packageDataDeleter.init(DATA_HOLDER);
        packageCacheDeleter.init(DATA_HOLDER);
        apkDeleter.init(DATA_HOLDER);
        otherDataDeleter.init(DATA_HOLDER);

        autoUninstallManager = AutoUninstallFactory.factory.create(mContext);
    }

    @Override
    public void setCleanerListener(CleanerListener listener) {
        this.listener = listener;
    }

    @Override
    public void startScan() {
        DATA_HOLDER.reset(listener);
        scanRunner.start(this, DATA_HOLDER);
    }

    @Override
    public void stopScan() {
        scanRunner.stop();
    }

    @Override
    public DataHolder.ApkRubbish getApkRubbish() {
        return DATA_LOADER.getApkRubbish();
    }

    @Override
    public DataHolder.PackageCache getPackageCache() {
        return DATA_LOADER.getPackageCache();
    }

    @Override
    public DataHolder.PackageData getPackageData() {
        return DATA_LOADER.getPackageData();
    }

    @Override
    public DataHolder.OtherData getOtherData() {
        return DATA_LOADER.getOtherData();
    }

    @Override
    public PackageDataDeleterFactory.PackageDataDeleter getPackageDataDeleter() {
        return packageDataDeleter;
    }

    @Override
    public PackageCacheDeleterFactory.PackageCacheDeleter getPackageCacheDeleter() {
        return packageCacheDeleter;
    }

    @Override
    public ApkDeleterFactory.ApkDeleter getApkDeleter() {
        return apkDeleter;
    }

    @Override
    public OtherDataDeleterFactory.OtherDataDeleter getOtherDataDeleter() {
        return otherDataDeleter;
    }

    @Override
    public void onScanStart() {
        if (listener != null)
            listener.onScanStart();
    }

    @Override
    public void onScanEnd(AbstractScanner run) {

    }

    @Override
    public void onScanAllEnd() {
        if (listener != null)
            listener.onScanEnd();
    }

    @Override
    public long clearAllApkRubbish() {
        final AsyncReturn<Long> ret = new AsyncReturn<Long>(Long.valueOf(0));
        final DataHolder.ApkRubbish apkRubbish = getApkRubbish();
        List<String> apkList = new ArrayList<>();
        //从空间管理首页清除apk，只清除该apk已安装且apk版本号小于等于已安装应用的版本号。
        if (apkRubbish != null) {
            PackageManager pm = mContext.getPackageManager();
            PackageInfo packageInfo = null;
            for (String s : apkRubbish.apks.keySet()) {
                try {
                    apkList.add(s);
                    packageInfo = pm.getPackageArchiveInfo(s, PackageManager.GET_ACTIVITIES);
                    if (packageInfo != null) {
                        boolean isInstalled = isPackageInstalled(mContext, packageInfo.packageName);
                        if (!isInstalled) {
                            //未安装，不删
                            apkList.remove(s);
                        } else {
                            //已安装，但apk版本号高于本机，不删
                            if (pm.getPackageInfo(packageInfo.packageName, 0).versionCode < packageInfo.versionCode)
                                apkList.remove(s);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        if (apkList != null && apkList.size() > 0)

        {
            for (String path : apkList)
                Log.d("aclean", " path:" + path);
            final CountDownLatch latch = new CountDownLatch(1);
            getApkDeleter().delete(mContext, apkList, new ApkDeleterFactory.ApkDeleter.ApkDeleterListener() {

                @Override
                public void onApkDeleterStart(boolean isMutils, List<String> apk) {
                }

                @Override
                public void onApkDeleterEnd(boolean isMutils, List<String> apk, boolean result, long size) {
                    ret.set(size);
                    latch.countDown();
                }
            });
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return ret.get();
    }

    @Override
    public long clearAllPackageData() {
        final AsyncReturn<Long> ret = new AsyncReturn<Long>(Long.valueOf(0));
        final DataHolder.PackageData data = getPackageData();
        if (data != null) {
            if (data.datas != null && data.datas.size() > 0) {
                for (DataHolder.SinglePackageData sp : data.datas)
                    Log.d("pclean", " pkg:" + sp.packageName + " size:" + sp.size);
            }
            final CountDownLatch latch = new CountDownLatch(1);
            getPackageDataDeleter().delete(mContext, data.datas, new PackageDataDeleterFactory.PackageDataDeleter.PackageDataDeleterListener() {
                @Override
                public void onPackageDataDeleterAllStart() {

                }

                @Override
                public void onPackageDataDeleterStart(String packageName) {

                }

                @Override
                public void onPackageDataDeleterEnd(String packageName, boolean result, long size) {

                }

                @Override
                public void onPackageDataDeleterAllEnd() {
                    ret.set(data.size);
                    latch.countDown();
                }
            });
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return ret.get();
    }

    @Override
    public long clearAllPackageCache() {
        final AsyncReturn<Long> ret = new AsyncReturn<Long>(Long.valueOf(0));
        final DataHolder.PackageCache cache = getPackageCache();
        if (cache != null) {
            if (cache.caches != null && cache.caches.size() > 0) {
                for (DataHolder.SinglePackageCache sp : cache.caches)
                    Log.d("cclean", " pkg:" + sp.packageName + " size:" + sp.size);
            }
            final CountDownLatch latch = new CountDownLatch(1);
            getPackageCacheDeleter().delete(mContext, cache.caches, new PackageCacheDeleterFactory.PackageCacheDeleter.PackageCacheDeleterListener() {
                @Override
                public void onPackageCacheDeleterAllStart() {

                }

                @Override
                public void onPackageCacheDeleterStart(String packageName) {

                }

                @Override
                public void onPackageCacheDeleterEnd(String packageName, boolean result, long size) {

                }

                @Override
                public void onPackageCacheDeleterAllEnd() {
                    ret.set(cache.size);
                    latch.countDown();
                }
            });
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return ret.get();
    }

    @Override
    public long clearAllOtherData() {
        final AsyncReturn<Long> ret = new AsyncReturn<Long>(Long.valueOf(0));
        final DataHolder.OtherData oData = getOtherData();
        List<String> apkList = null;
        if (oData != null)
            apkList = new ArrayList<String>(oData.datas.keySet());
        if (apkList != null && apkList.size() > 0) {
            for (String path : apkList)
                Log.d("oclean", " path:" + path);
            final CountDownLatch latch = new CountDownLatch(1);
            getOtherDataDeleter().delete(mContext, apkList, new OtherDataDeleterFactory.OtherDataDeleter.OtherDataDeleterListener() {
                @Override
                public void onOtherDeleteStart() {
                }

                @Override
                public void onOtherDataDeleteEnd(boolean result, long size) {
                    ret.set(size);
                    latch.countDown();
                }
            });
            try {
                latch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        return ret.get();
    }

    private static Timer mCheckTimer = null;
    @Override
    public void unInstallApp(final int time) {
        if (mCheckTimer != null)
            mCheckTimer.cancel();
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    TimerTask checkTask = new TimerTask() {
                        @Override
                        public void run() {
                            final String topPkgName = getTopPackageName(mContext);
                            Log.d("autoclean", " topPkgName:" + topPkgName);
                            if (!topPkgName.equals("com.tianci.appstore")) {
                                try {
                                    autoUninstallManager.autoUninstall(time,topPkgName);
                                    if (mCheckTimer != null)
                                        mCheckTimer.cancel();
                                } catch (Exception e) {
                                    e.printStackTrace();
                                }
                            }
                        }
                    };
                    mCheckTimer = new Timer();
                    mCheckTimer.schedule(checkTask, 2000, 3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    @Override
    public int getServerCommand() {
        return autoUninstallManager.getServerCommand();
    }

    @Override
    public void resetCommandSuccess() {
        autoUninstallManager.resetCommandSuccess();
    }

    @Override
    public void setOnAutoUninstallSuccessListener(OnAutoUninstallSuccessListener listener) {
        autoUninstallManager.setOnAutoUninstallSuccessListener(listener);
    }


    private Thread cleanAllThread = null;

    @Override
    public synchronized void cleanAll() {
        if (cleanAllThread == null) {
            cleanAllThread = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        if (listener != null)
                            listener.onCleanAllStart();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    long size = 0;
                    size += clearAllApkRubbish();
                    size += clearAllPackageData();
                    size += clearAllPackageCache();
                    size += clearAllOtherData();
                    try {
                        if (listener != null)
                            listener.onCleanAllEnd(size);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    synchronized (CleanerImpl.this) {
                        cleanAllThread = null;
                    }
                }
            });
            cleanAllThread.start();
        }
    }

    public static boolean isPackageInstalled(Context context, String pkg) {
        PackageManager mPackageManager = context.getApplicationContext().getPackageManager();
        PackageInfo intent;
        try {
            intent = mPackageManager.getPackageInfo(pkg, 0);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
        if (intent == null)
            return false;
        else
            return true;
    }

    private static String getTopPackageName(Context context) {
        String pkgName = null;
        ActivityManager manager = ((ActivityManager)context.getSystemService(Context.ACTIVITY_SERVICE));

        try {
            if (Build.VERSION.SDK_INT >= 21) {
                List<ActivityManager.RunningAppProcessInfo> pis = manager.getRunningAppProcesses();
                ActivityManager.RunningAppProcessInfo topAppProcess = pis.get(0);
                if (topAppProcess != null && topAppProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {
                    if(topAppProcess.pkgList != null && topAppProcess.pkgList.length > 0) {
                        return topAppProcess.pkgList[0];
                    } else {
                        pkgName = topAppProcess.processName;
                    }
                }
            } else {
                //getRunningTasks() is deprecated since API Level 21 (Android 5.0)
                List localList = manager.getRunningTasks(1);
                ActivityManager.RunningTaskInfo localRunningTaskInfo = (ActivityManager.RunningTaskInfo)localList.get(0);
                pkgName = localRunningTaskInfo.topActivity.getPackageName();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return pkgName;
    }
}
